package com.wenx.v3system.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.web.SecurityFilterChain;

/**
 * @author wenx
 * @description OAuth2 资源服务器安全配置
 * 配置 v3-system 作为 OAuth2 资源服务器，验证来自 v3-auth 的 JWT 令牌
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class ResourceServerConfig {

    private final JwtDecoder jwtDecoder;
    private final CustomJwtConverter customJwtAuthenticationConverter;

    public ResourceServerConfig(JwtDecoder jwtDecoder, 
                              CustomJwtConverter customJwtAuthenticationConverter) {
        this.jwtDecoder = jwtDecoder;
        this.customJwtAuthenticationConverter = customJwtAuthenticationConverter;
    }

    /**
     * 公共资源过滤器链 - 处理不需要认证的资源
     */
    @Bean
    @Order(1)
    public SecurityFilterChain publicResourcesFilterChain(HttpSecurity http) throws Exception {
        http
                // 禁用 CSRF，因为我们使用 JWT
                .csrf(AbstractHttpConfigurer::disable)

                // 配置会话管理为无状态
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

                // 只处理公共资源路径
                .securityMatchers(matchers -> matchers
                        .requestMatchers(
                                // OPTIONS 请求（CORS预检请求）- 仅限API路径
                                org.springframework.http.HttpMethod.OPTIONS,
                                "/api/**"
                        )
                        .requestMatchers(
                                // 健康检查和监控端点
                                "/actuator/**",
                                "/health/**",
                                "/info/**",
                                "/metrics/**",
                                "/favicon.ico"
                        )
                        .requestMatchers(
                                // Swagger文档和API文档
                                "/swagger-ui/**",
                                "/swagger-ui.html",
                                "/v3/api-docs/**",
                                "/swagger-resources/**",
                                "/webjars/**"
                        )
                        .requestMatchers(
                                // 静态资源和页面路径
                                "/",
                                "/index",
                                "/home",
                                "/login",
                                "/login-redirect",
                                "/oauth2/callback",
                                "/oauth2/jwks",
                                "/error",
                                "/dashboard",
                                "/admin",
                                "/fallback"
                        )
                        .requestMatchers(
                                // 静态资源文件
                                "/css/**",
                                "/js/**",
                                "/images/**",
                                "/img/**",
                                "/fonts/**",
                                "/static/favicon.ico",
                                "/static/**",
                                "/public/**",
                                "/assets/**"
                        )
                )

                // 配置授权规则 - 所有匹配的路径都允许匿名访问
                .authorizeHttpRequests(authz -> authz
                        .anyRequest().permitAll()
                );

        return http.build();
    }


    /**
     * 安全API过滤器链 - 处理需要JWT认证的API
     */
    @Bean
    @Order(2)
    public SecurityFilterChain secureApiFilterChain(HttpSecurity http) throws Exception {
        http
                // 禁用 CSRF，因为我们使用 JWT
                .csrf(AbstractHttpConfigurer::disable)

                // 配置会话管理为无状态
                .sessionManagement(session -> 
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

                // 显式限定匹配范围为 /api/ 和 /system/ 路径
                .securityMatchers(matchers -> matchers
                        .requestMatchers("/api/**", "/system/**")
                )

                // 配置授权规则
                .authorizeHttpRequests(authz -> authz
                        // 认证相关接口 - 允许匿名访问
                        .requestMatchers("/api/v3/sys/auth/**", "/system/api/v3/sys/auth/**").permitAll()
                        .requestMatchers("/api/v3/platform/auth/**", "/system/api/v3/platform/auth/**").permitAll()
                        
                        // 远程服务调用接口，需要客户端凭据授权
                        .requestMatchers("/api/v3/sys/user/remote/**", "/system/api/v3/sys/user/remote/**")
                        .hasAuthority("SCOPE_read")

                        // 平台用户远程服务调用接口，需要客户端凭据授权
                        .requestMatchers("/api/v3/platform/user/remote/**", "/system/api/v3/platform/user/remote/**")
                        .hasAuthority("SCOPE_read")

                        // 其他所有API请求都需要认证
                        .anyRequest().authenticated()
                )

                // 配置 OAuth2 资源服务器，使用 JWT 验证
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt -> jwt
                                .decoder(jwtDecoder)
                                .jwtAuthenticationConverter(customJwtAuthenticationConverter)
                        )
                );
        
        return http.build();
    }
}